from django import forms
from django.conf import settings
from django.shortcuts import render, redirect
from django.urls import re_path, reverse
from django.utils.safestring import mark_safe

from stark.service.v1 import StarkHandler, Option
from web import models
from web.utils.queryset import get_subnet_queryset


class HostRecycleForm(forms.Form):
    note = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control'}), label='回收原因', required=True)


class HostAllocateForm(forms.Form):
    ip_type = forms.ChoiceField(
        label='IP地址类型',
        choices=[(None, '--------')],
        widget=forms.Select(attrs={'class': 'form-control'}),
        required=True
    )
    app_name = forms.CharField(label='设备名称/应用名称', widget=forms.TextInput(attrs={'class': 'form-control'}),
                               required=True)
    depart = forms.ChoiceField(
        label='部门',
        choices=[],
        widget=forms.RadioSelect(attrs={'class': 'clearfix'}),
        required=True
    )
    location = forms.CharField(label='位置', widget=forms.TextInput(attrs={'class': 'form-control'}), required=True)
    responsible_person = forms.CharField(label='责任人', widget=forms.TextInput(attrs={'class': 'form-control'}),
                                         required=True)
    note = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control'}), label='分配原因', required=False)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['ip_type'].choices += models.AssetType.objects.exclude(
            id__in=[settings.NET_ADDR_IP_TYPE, settings.UNUSE_IP_TYPE, settings.BROADCAST_ADDR_IP_TYPE]).values_list(
            'id',
            'title')
        self.fields['depart'].choices += models.Depart.objects.values_list('id', 'title')


class HostsHandler(StarkHandler):
    change_template = 'web/change.html'

    def display_record(self, obj=None, is_header=None, *args, **kwargs):
        """
        显示主机分配记录
        :param obj:
        :param is_header:
        :param args:
        :param kwargs:
        :return:
        """
        if is_header:
            return "使用记录"
        record_url = reverse('stark:web_hostrecord_list', kwargs={'host_id': obj.id})
        return mark_safe("<a href='%s'>分配记录</a>" % record_url)

    list_display = [
        'ip_address',
        'ip_subnet',
        'location',
        'ip_type',
        'app_name',
        'depart',
        'responsible_person',
        'last_change_date',
        display_record,
    ]

    def get_urls(self):
        """
        二次路由分发
        :return:
        """
        patterns = [
            re_path(r'^list/$', self.wrapper(self.list_view), name=self.get_list_url_name),
            # re_path(r'^add/(?P<subnet_id>\d+)/$', self.wrapper(self.add_view), name=self.get_add_url_name),
            # re_path(r'^change/(?P<pk>\d+)/$', self.wrapper(self.change_view),
            #         name=self.get_change_url_name),
            # re_path(r'^delete/(?P<pk>\d+)/$', self.wrapper(self.delete_view),
            #         name=self.get_delete_url_name)
            re_path(r'^allocate/(?P<pk>\d+)/$', self.wrapper(self.allocate_view),
                    name=self.get_url_name('allocate')),
            re_path(r'^recycle/(?P<pk>\d+)/$', self.wrapper(self.recycle_view),
                    name=self.get_url_name('recycle')),
        ]
        patterns.extend(self.extra_url())
        return patterns

    def display_allocate_and_recycle(self, obj=None, is_header=None, *args, **kwargs):
        """
        同时显分配与回收按钮
        :param obj:
        :param is_header:
        :return:
        """
        if is_header:
            return '操作'
        tpl = "<a href='%s'>分配</a> | <a href='%s'>回收</a>" % (
            self.reverse_allocate_url(pk=obj.id),
            self.reverse_recycle_url(pk=obj.id)
        )
        return mark_safe(tpl)

    def display_allocate(self, obj=None, is_header=None, *args, **kwargs):
        """
        显示分配按钮
        :param obj:
        :param is_header:
        :param args:
        :param kwargs:
        :return:
        """
        if is_header:
            return '操作'
        return mark_safe("<a href='%s'>分配</a>" % self.reverse_allocate_url(pk=obj.id))

    def display_recycle(self, obj=None, is_header=None, *args, **kwargs):
        """
        显示分配按钮
        :param obj:
        :param is_header:
        :param args:
        :param kwargs:
        :return:
        """
        if is_header:
            return '操作'
        return mark_safe("<a href='%s'>回收</a>" % self.reverse_recycle_url(pk=obj.id))

    def reverse_allocate_url(self, *args, **kwargs):
        return self.reverse_commons_url(self.get_url_name('allocate'), *args, **kwargs)

    def reverse_recycle_url(self, *args, **kwargs):
        return self.reverse_commons_url(self.get_url_name('recycle'), *args, **kwargs)

    def allocate_view(self, request, pk, *args, **kwargs):
        """
        主机分配页面
        :param request:
        :param pk:
        :return:
        """
        origin_url = self.reverse_list_url(*args, **kwargs)
        model_form_class = HostAllocateForm
        current_object = self.get_change_object(request, pk, *args, **kwargs)
        if not current_object:
            info = '数据不存在，请重新选择!'
            return render(request, 'stark/hint.html', {'msg': info, 'return_url': origin_url})
        if current_object.ip_type_id in [settings.NET_ADDR_IP_TYPE, settings.BROADCAST_ADDR_IP_TYPE]:
            info = '网络地址和广播地址不能分配，请重新选择!'
            return render(request, 'stark/hint.html', {'msg': info, 'return_url': origin_url})
        current_user_id = request.session['user_info']['user_id']
        current_user_object = models.UserInfo.objects.filter(pk=current_user_id).first()
        if request.method == "GET":
            form = model_form_class(initial={'depart': current_user_object.depart_id})
            return render(request, self.change_template or 'stark/change.html', {'form': form})
        form = model_form_class(data=request.POST)
        if form.is_valid():
            ip_type = form.cleaned_data['ip_type']
            depart = form.cleaned_data['depart']
            location = form.cleaned_data['location']
            responsible_person = form.cleaned_data['responsible_person']
            app_name = form.cleaned_data['app_name']
            note = form.cleaned_data['note']
            current_object.ip_type_id = ip_type
            current_object.depart_id = depart
            current_object.location = location
            current_object.responsible_person = responsible_person
            current_object.app_name = app_name
            current_object.save()

            # 插入IP分配记录
            ip = current_object.id
            ip_subnet_id = current_object.ip_subnet_id
            ip_address = current_object.ip_address
            depart = depart
            app_name = app_name
            location = location
            note = note
            responsible_person = responsible_person
            operate_person = current_user_id
            host_record_object = models.HostRecord(
                ip_id=ip,
                ip_subnet_id=ip_subnet_id,
                ip_address=ip_address,
                depart_id=depart,
                app_name=app_name,
                location=location,
                note=note,
                responsible_person=responsible_person,
                operate_person_id=operate_person,
                operate_type=1
            )
            host_record_object.save()
            return redirect(self.reverse_list_url(*args, **kwargs))
        return render(request, self.change_template or 'stark/change.html', {'form': form})

    def recycle_view(self, request, pk, *args, **kwargs):
        """
        主机回收页面
        :param request:
        :param pk:
        :param args:
        :param kwargs:
        :return:
        """
        origin_url = self.reverse_list_url(*args, **kwargs)
        model_form_class = HostRecycleForm
        current_object = self.get_change_object(request, pk, *args, **kwargs)
        if not current_object:
            info = '要修改的数据不存在，请重新选择!'
            return render(request, 'stark/hint.html', {'msg': info, 'return_url': origin_url})
        if current_object.ip_type_id in [settings.NET_ADDR_IP_TYPE, settings.BROADCAST_ADDR_IP_TYPE]:
            info = '网络地址和广播地址不能回收，请重新选择!'
            return render(request, 'stark/hint.html', {'msg': info, 'return_url': origin_url})
        if current_object.ip_type_id == settings.UNUSE_IP_TYPE:
            info = 'IP地址未分配，不需要回收!'
            return render(request, 'stark/hint.html', {'msg': info, 'return_url': origin_url})
        if request.method == "GET":
            form = model_form_class()
            return render(request, self.change_template or 'stark/change.html', {'form': form})
        form = model_form_class(data=request.POST)
        if form.is_valid():
            note = form.cleaned_data['note']
            current_object.ip_type_id = settings.UNUSE_IP_TYPE
            current_object.depart_id = None
            current_object.location = ''
            current_object.responsible_person = ''
            current_object.app_name = ''
            current_object.save()

            # 创建IP地址回收记录
            current_user_id = request.session['user_info']['user_id']
            models.HostRecord.objects.create(
                ip_id=pk,
                ip_subnet_id=current_object.ip_subnet_id,
                ip_address=current_object.ip_address,
                operate_person_id=current_user_id,
                operate_type=0,
                depart=None,
                note=note
            )
            return redirect(self.reverse_list_url(*args, **kwargs))
        return render(request, self.change_template or 'stark/change.html', {'form': form})

    def get_add_btn(self, request, *args, **kwargs):
        return None

    def get_list_display(self, request, *args, **kwargs):
        """
        预留列表页面显示字段的钩子函数
        :return:
        """
        value = []
        if self.list_display:
            value.extend(self.list_display)
            permission_dict = request.session.get(settings.MOBILEDJ_PERMISSION_SESSION_KEY)
            if self.get_url_name('allocate') in permission_dict and self.get_url_name('recycle') in permission_dict:
                value.append(type(self).display_allocate_and_recycle)
            elif self.get_url_name('allocate') in permission_dict:
                value.append(type(self).display_allocate)
            elif self.get_url_name('recycle') in permission_dict:
                value.append(type(self).display_recycle)
        return value

    search_list = ['ip_address__contains', 'app_name__contains', 'responsible_person__contains',
                   'ip_subnet__subnet__contains', 'ip_subnet__location__contains']
    search_group = [Option('ip_type', is_multi=True)]
    order_list = ['ip_address_num']

    def get_queryset(self, request, *args, **kwargs):
        current_user_id = request.session['user_info']['user_id']
        user_object = models.UserInfo.objects.filter(id=current_user_id).first()
        queryset = models.Hosts.objects.exclude(ip_subnet__service_type=settings.UNUSE_SERVICE_TYPE)
        if not user_object.is_depart:
            return queryset
        subnet_queryset_list = get_subnet_queryset().filter(depart=user_object.depart)
        subnet_list = [item.id for item in subnet_queryset_list]
        queryset = queryset.filter(ip_subnet_id__in=subnet_list)
        return queryset
